package p17_从advisor到aspect;

import org.aspectj.lang.annotation.*;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.*;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.core.annotation.MergedAnnotations;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 前面我们得知，高级切面，最终都会转为低级切面
 * 这一节介绍是如何转换的
 */
public class _3_高级切面转换成低级切面 {
    public static void main(String[] args) {
        /**
         * 高级切面转低级切面
         * 本质就是解析高级切面类，将每一个方法封装成一个低级切面
         * 下面以@Before为例进行解析，其他类型的通知同理
         */
        List<Advisor> list = new Aspect2Advisor().convert(new MyAspect());
        System.out.println(list);
        //本质还是通过反射
    }

    public static class Aspect2Advisor {
        /**
         * 将传入的aspect对象，转为若干个advisor对象
         *
         * @param aspect aspect对象
         * @return advisor对象数组
         */
        public List<Advisor> convert(Object aspect) {
            //切面工厂，使用这个工厂可以拿到aspect这个切面对象
            AspectInstanceFactory factory = new SingletonAspectInstanceFactory(aspect);
            //收集低级切面的集合
            List<Advisor> list = new ArrayList<>();

            //判断aspect有没有加@Aspect注解
            if (aspect.getClass().isAnnotationPresent(Aspect.class)) {
                //循环结束，就将aspect这个高级切面转成了若干个低级切面
                for (Method method : aspect.getClass().getDeclaredMethods()) {
                    if (method.isAnnotationPresent(Before.class)) {
                        //解析切点
                        String value = method.getAnnotation(Before.class).value();
                        AspectJExpressionPointcut pt = new AspectJExpressionPointcut();
                        pt.setExpression(value);
                        //通知类(与前面的MethodInterceptor接口类似，都是实现(继承)了Advice接口)，根据注解不同，可以选择不同的通知实现类
                        AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(method, pt, factory);
                        //低级切面
                        Advisor advisor = new DefaultPointcutAdvisor(pt, advice);
                        list.add(advisor);
                    } else if (method.isAnnotationPresent(AfterReturning.class)) {
                        String value = method.getAnnotation(AfterReturning.class).value();
                        AspectJExpressionPointcut pt = new AspectJExpressionPointcut();
                        pt.setExpression(value);
                        AspectJAfterReturningAdvice advice = new AspectJAfterReturningAdvice(method, pt, factory);
                        Advisor advisor = new DefaultPointcutAdvisor(pt, advice);
                        list.add(advisor);
                    } else if (method.isAnnotationPresent(Around.class)) {
                        String value = method.getAnnotation(Around.class).value();
                        AspectJExpressionPointcut pt = new AspectJExpressionPointcut();
                        pt.setExpression(value);
                        AspectJAroundAdvice advice = new AspectJAroundAdvice(method, pt, factory);
                        Advisor advisor = new DefaultPointcutAdvisor(pt, advice);
                        list.add(advisor);
                    } else if (method.isAnnotationPresent(After.class)) {
                        String value = method.getAnnotation(After.class).value();
                        AspectJExpressionPointcut pt = new AspectJExpressionPointcut();
                        pt.setExpression(value);
                        AspectJAfterAdvice advice = new AspectJAfterAdvice(method, pt, factory);
                        Advisor advisor = new DefaultPointcutAdvisor(pt, advice);
                        list.add(advisor);
                    }
                }
            }

            return list;
        }
    }
}
